from pathlib import Path
from typing import Any
import logging
from kubernetes import config, client
from performance.runner.logger import create_sample_logger, create_detail_logger
from performance.runner.constants import KUBECONFIG_PATH, RESOURCE_MONITOR_TASK_CASE_NAME
from performance.runner.resource_monitor.log_parser import ResourceLogParser
from .kubeconfig_fetcher import fetch_and_save_kubeconfig, validate_kubeconfig


class ResourceMonitor:
    def __init__(self, feature_category: str, pod_resource_dict, step_logger: logging.Logger, resource_log_path: Path,
        enable_detail_logging: bool = False):
        # 保存步骤日志记录器
        self._step_logger = step_logger
        self._sample_logger = create_sample_logger(resource_log_path, feature_category)
        self.enable_detail_logging = enable_detail_logging
        self._detail_logger = None
        if self.enable_detail_logging:
            self._detail_logger = \
                create_detail_logger(resource_log_path, feature_category, RESOURCE_MONITOR_TASK_CASE_NAME)
            self._step_logger.info(f'Detail logging enabled')

        self._feature_category = feature_category
        self._pod_resource_dict = pod_resource_dict

        # 优先加载项目目录下 kubeconfig 文件
        if not KUBECONFIG_PATH.exists():
            self._step_logger.info("本地 kubeconfig 文件不存在，尝试自动拉取远程 kubeconfig 文件...")
            fetch_and_save_kubeconfig()
        config.load_kube_config(config_file=str(KUBECONFIG_PATH))
        # 二次验证 kubeconfig 文件有效性
        if not validate_kubeconfig(self._step_logger):
            self._step_logger.error(f"当前 kubeconfig 不可用。")
            fetch_and_save_kubeconfig()
            if not validate_kubeconfig(self._step_logger):
                self._step_logger.error(f"远端服务器 kubeconfig 文件内容无效，无法访问集群。")

        self._v1 = client.CoreV1Api()
        self._metrics_api = client.CustomObjectsApi()

        self.log_parser = ResourceLogParser(resource_log_path, self._step_logger)
    
    @property
    def feature_category(self):
        """获取特性类别（只读）"""
        return self._feature_category

    @property
    def step_logger(self):
        """获取步骤日志记录器（只读）"""
        return self._step_logger

    @property
    def sample_logger(self):
        """获取样本日志记录器（只读）"""
        return self._sample_logger

    @property
    def pod_resource_dict(self):
        """获取 pod 资源字典（只读）"""
        return self._pod_resource_dict.copy()

    def monitor_pod_resources(self):
        """
        获取并更新监控 pod 的 CPU 和内存资源占用。
        遍历所有命名空间下的 pod，只处理在 pod_resource_dict 中登记的 pod。
        更新 pod_resource_dict 中对应 pod 的 cpu 和 mem 字段。
        :return: None
        """
        self._step_logger.info(f"进行 {self._feature_category} 资源监控数据采集。")
        pods = self._v1.list_pod_for_all_namespaces(watch=False)
        if self.enable_detail_logging and self._detail_logger is not None:
            self._detail_logger.info('=' * 80)
        for pod in pods.items:
            namespace = pod.metadata.namespace
            name = pod.metadata.name

            monitor_pod = self._pod_resource_dict.get(f"{namespace}_{name}")
            if not monitor_pod:
                continue
            try:
                metrics: Any = self._metrics_api.get_namespaced_custom_object(
                    group="metrics.k8s.io",
                    version="v1beta1",
                    namespace=namespace,
                    plural="pods",
                    name=name
                )
                if self.enable_detail_logging and self._detail_logger is not None:
                    self._detail_logger.info(f" {namespace} - {name}'s metrics: \n {metrics}")
                usage = metrics['containers'][0]['usage']
                monitor_pod['cpu'] = usage.get('cpu', 'N/A')
                monitor_pod['mem'] = usage.get('memory', 'N/A')
            except Exception as e:
                self._step_logger.error(f"资源数据采集时，获取 {namespace}-{name} 资源占用失败: {e}")
        self._export_pod_resource_data()

    def _export_pod_resource_data(self):
        """
        导出 pod 资源数据到日志。
        :return: None
        """
        self._sample_logger.info('=' * 80)
        for pod, resource in self._pod_resource_dict.items():
            pod_info = pod.split('_', 1)
            self._sample_logger.info(
                f"namespace: {pod_info[0]}, Pod: {pod_info[1]}, CPU占用: {resource['cpu']} , 内存占用: {resource['mem']}")
            resource['cpu'] = None
            resource['mem'] = None
        self._sample_logger.info('=' * 80)